#include "stdafx.h"
#include "Dx11app.h"
#define MAX_LOADSTRING 100
#include "req.h"
#include "Input.h"

#include <process.h>
namespace FIRSTDX
{

	// Global Variables:
	HINSTANCE hInst;								// current instance
	TCHAR szTitle[MAX_LOADSTRING];					// The title bar text
	TCHAR szWindowClass[MAX_LOADSTRING];			// the main window class name


	// Message handler for about box.
	INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
	{
		UNREFERENCED_PARAMETER(lParam);
		switch (message)
		{
		case WM_INITDIALOG:
			return (INT_PTR)TRUE;

		case WM_COMMAND:
			if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
			{
				EndDialog(hDlg, LOWORD(wParam));
				return (INT_PTR)TRUE;
			}
			break;
		}
		return (INT_PTR)FALSE;
	}


	//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
	//
	//  PURPOSE:  Processes messages for the main window.
	//
	//  WM_COMMAND	- process the application menu
	//  WM_PAINT	- Paint the main window
	//  WM_DESTROY	- post a quit message and return
	//
	//
	LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
	{
		int wmId, wmEvent;
		PAINTSTRUCT ps;
		HDC hdc;

		switch (message)
		{
		case WM_COMMAND:
			wmId    = LOWORD(wParam);
			wmEvent = HIWORD(wParam);
			// Parse the menu selections:
			switch (wmId)
			{
			case IDM_ABOUT:
				DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
				break;
			case IDM_EXIT:
				DestroyWindow(hWnd);
				break;
			default:
				return DefWindowProc(hWnd, message, wParam, lParam);
			}
			break;
		case WM_PAINT:
			hdc = BeginPaint(hWnd, &ps);
			// TODO: Add any drawing code here...
			EndPaint(hWnd, &ps);
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		return 0;
	}



	//
	//  FUNCTION: MyRegisterClass()
	//
	//  PURPOSE: Registers the window class.
	//
	//  COMMENTS:
	//
	//    This function and its usage are only necessary if you want this code
	//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
	//    function that was added to Windows 95. It is important to call this function
	//    so that the application will get 'well formed' small icons associated
	//    with it.
	//
	ATOM MyRegisterClass(HINSTANCE hInstance)
	{
		WNDCLASSEX wcex;

		wcex.cbSize = sizeof(WNDCLASSEX);

		wcex.style			= CS_HREDRAW | CS_VREDRAW;
		wcex.lpfnWndProc	= WndProc;
		wcex.cbClsExtra		= 0;
		wcex.cbWndExtra		= 0;
		wcex.hInstance		= hInstance;
		wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_THREADING));
		wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
		wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
		wcex.lpszMenuName	= nullptr;//MAKEINTRESOURCE(IDC_THREADING);
		wcex.lpszClassName	= szWindowClass;
		wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

		return RegisterClassEx(&wcex);
	}

	//
	//   FUNCTION: InitInstance(HINSTANCE, int)
	//
	//   PURPOSE: Saves instance handle and creates main window
	//
	//   COMMENTS:
	//
	//        In this function, we save the instance handle in a global variable and
	//        create and display the main program window.
	//
	HWND InitInstance(HINSTANCE hInstance, int nCmdShow, int width, int height)
	{
		HWND hWnd;


		RECT _windowRect = { 0, 0, width, height };
		AdjustWindowRectEx(&_windowRect,WS_OVERLAPPEDWINDOW,NULL,CW_USEDEFAULT);

		hWnd = CreateWindowEx(WS_EX_CONTROLPARENT,szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
			CW_USEDEFAULT, 0, (_windowRect.right - _windowRect.left),
			(_windowRect.bottom - _windowRect.top), NULL, NULL, hInstance, NULL);

		if (!hWnd)
		{
			return FALSE;
		}

 


		hInst = hInstance; // Store instance handle in our global variable

 

		ShowWindow(hWnd, nCmdShow);
		UpdateWindow(hWnd);

		return hWnd;
	}



	void Dx11app::InitDx11(uint width,
					 uint height,
					 uint freshRate,//hard code 60
					 HWND window,
					 bool fullscreen)
	{

		DXGI_SWAP_CHAIN_DESC sd =
		{
			{ width, height, { 60, 1 }, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED, DXGI_MODE_SCALING_UNSPECIFIED },
			{ 1, 0 },
			DXGI_USAGE_RENDER_TARGET_OUTPUT,
			1,
			window,
			!fullscreen,
			DXGI_SWAP_EFFECT_DISCARD,
			0
		};

		D3D_FEATURE_LEVEL featurelevels[] = 
		{
			D3D_FEATURE_LEVEL_11_0,
			D3D_FEATURE_LEVEL_10_1,
			D3D_FEATURE_LEVEL_10_0,
		};

		D3D_FEATURE_LEVEL featurelevelpicked ;

		uint createdeviceflags = 0;
#ifdef _DEBUG
		//createdeviceflags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

		HV(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, createdeviceflags, featurelevels, sizeof(featurelevels)/sizeof(D3D_FEATURE_LEVEL), D3D11_SDK_VERSION,
			&sd, &m_swapChain, &m_device, &featurelevelpicked, &m_context));


		ID3D11Texture2D *backbuffer;
		HV(m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)&backbuffer));
		HV(m_device->CreateRenderTargetView(backbuffer, NULL, &m_rtview));
		HV(backbuffer->Release());

		D3D11_TEXTURE2D_DESC desc =
		{
			width, height,
			1, 1,
			DXGI_FORMAT_D32_FLOAT,
			{ 1, 0 },
			D3D11_USAGE_DEFAULT,
			D3D11_BIND_DEPTH_STENCIL,
			0, 0
		};
		ID3D11Texture2D *tex = NULL;
		HV(m_device->CreateTexture2D(&desc, NULL, &tex));

		//////////////////////////////////////////////////////////////////////////
		// Initialize the description of the stencil state.
		D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
		ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));

		// Set up the description of the stencil state.
		depthStencilDesc.DepthEnable = true;
		depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
		depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS;

		depthStencilDesc.StencilEnable = true;
		depthStencilDesc.StencilReadMask = 0xFF;
		depthStencilDesc.StencilWriteMask = 0xFF;

		// Stencil operations if pixel is front-facing.
		depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
		depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
		depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
		depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

		// Stencil operations if pixel is back-facing.
		depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
		depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
		depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
		depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
		
		HV(m_device->CreateDepthStencilState(&depthStencilDesc, &depthStencilState));
		// Set the depth stencil state.
		m_context->OMSetDepthStencilState(depthStencilState, 1);
		
		D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc;
		// Initialize the depth stencil view.
		ZeroMemory(&depthStencilViewDesc, sizeof(depthStencilViewDesc));

		// Set up the depth stencil view description.
		depthStencilViewDesc.Format = desc.Format;
		depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
		depthStencilViewDesc.Texture2D.MipSlice = 0;


		HV(m_device->CreateDepthStencilView(tex, &depthStencilViewDesc, &m_dsview));
		HV(tex->Release());




		m_context->OMSetRenderTargets(1, &m_rtview, m_dsview);

		D3D11_RASTERIZER_DESC rasterizerstate = { D3D11_FILL_SOLID, D3D11_CULL_NONE, true, 0, 0, 0, true, false, false, false };
		HV(m_device->CreateRasterizerState(&rasterizerstate, &m_rs));
		m_context->RSSetState(m_rs); 

		D3D11_VIEWPORT viewport = {0, 0, static_cast<FLOAT>(width), static_cast<FLOAT>(height), 0, 1};
		m_context->RSSetViewports(1, &viewport);

	}

	Dx11app::Dx11app( HINSTANCE hInstance, int nCmdShow )
	{
		// Initialize global strings
		LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
		LoadString(hInstance, IDC_THREADING, szWindowClass, MAX_LOADSTRING);
		MyRegisterClass(hInstance);

		int width = 1440;
		int height = 900;
		// Perform application initialization:
		m_hWnd = InitInstance (hInstance, nCmdShow, width, height);
		if (!m_hWnd)
		{
			errorMsg("InitInstance() error","window error");
		}

		m_hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_THREADING));


		InitDx11(width,height,60,m_hWnd,false);
		
		//////////////////////////////////////////////////////////////////////////







	}

	Dx11app::~Dx11app()
	{
		if(m_device)m_device->Release();
		if(m_context)m_context->Release();
		if(m_swapChain)m_swapChain->Release();
		if(m_rtview)m_rtview->Release();
		if(m_dsview)m_dsview->Release();
		if(m_rs)m_rs->Release();
		if(m_inputLayout)m_inputLayout->Release();

		for (size_t i = 0; i< m_effectVec.size();++i)
		{
			m_effectVec[i]->Release();
		}
		m_effectVec.clear();

		HV(depthStencilState->Release());
	}

	int Dx11app::runMainLoop()
	{
		calculateCenter(m_hWnd);
		MSG msg;
		while (true)
		{
			if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
			{
				if (msg.message == WM_QUIT)
				{
					break;
				}
				if (!TranslateAccelerator(msg.hwnd, m_hAccelTable, &msg))
				{
					TranslateMessage(&msg);
					DispatchMessage(&msg);
				}
			}else
			{
				update();
			}
		}
		return (int)msg.wParam;
	}

	void Dx11app::update()
	{		

		float color[4] = {0.5f,0.6f,0.7f,0.8f}; 
		m_context->ClearRenderTargetView(m_rtview, color );
		m_context->ClearDepthStencilView(m_dsview,D3D11_CLEAR_DEPTH,1,0);
		updateFrame();
	}

	ID3DX11Effect* Dx11app::setupShaders(LPCTSTR fxName)
	{
		ID3D10Blob *fxblob = NULL, *errblob = NULL;
		if(FAILED(D3DX11CompileFromFile(fxName, NULL, NULL, "", "fx_5_0", 
			D3D10_SHADER_ENABLE_STRICTNESS, 0, NULL, &fxblob, &errblob, NULL))) 
		{
			Exit(errblob ? (char *)errblob->GetBufferPointer() : "fx file load");
			errblob->Release();
		}
		ID3DX11Effect* effect;
		HV(D3DX11CreateEffectFromMemory(fxblob->GetBufferPointer(), fxblob->GetBufferSize(), 0, m_device, &effect));
		fxblob->Release();
		
		return effect;

	}

	void Dx11app::swapBuffer( bool sync )
	{
		m_swapChain->Present(sync,0);
	}






}